// 熔断逻辑
const breakerMap = new Map<
  string,
  { failure: number; open: boolean; timer: number | null }
>();

/**
 * 检查指定电路是否处于打开状态
 *
 * @param key 电路的唯一标识符
 * @returns 如果电路处于打开状态则返回true，否则返回false
 */
export function isCircuitOpen(key: string): boolean {
  // 从breakerMap中获取与指定key关联的记录
  const record = breakerMap.get(key);
  // 如果记录存在且其open属性为true，则返回true；否则返回false
  // 使用null合并运算符提供默认值false，以处理record为undefined的情况
  return record?.open ?? false;
}

/**
 * 报告操作失败并根据失败次数和阈值决定是否启动熔断机制
 *
 * @param key 标识符，用于区分不同的熔断记录
 * @param threshold 失败阈值，达到此次数后启动熔断
 * @param cooldown 冷却时间，在此时间后熔断将被重置
 */
export function reportFailure(
  key: string,
  threshold: number,
  cooldown: number
) {
  // 从breakerMap中获取当前key对应的失败记录
  let record = breakerMap.get(key);
  // 如果没有找到记录，则创建一个新的记录并初始化
  if (!record) {
    record = { failure: 0, open: false, timer: null };
    breakerMap.set(key, record);
  }

  // 增加失败次数
  record.failure++;

  // 检查是否达到阈值且当前熔断状态未开启
  if (record.failure >= threshold && !record.open) {
    // 启用熔断并记录状态为开启
    record.open = true;
    console.warn(`熔断开启 [${key}]`);
    // 设置定时器，在指定的冷却时间后重置熔断状态
    record.timer = setTimeout(() => {
      record!.open = false;
      record!.failure = 0;
      console.log(`熔断恢复 [${key}]`);
    }, cooldown);
  }
}

/**
 * 重置断路器状态
 *
 * 此函数旨在重置特定断路器的状态，将其失败计数归零，关闭断路器，并清除任何正在运行的计时器
 * 它通过传入的键来识别并操作对应的断路器记录
 *
 * @param key 断路器的唯一标识符，用于从断路器映射中检索断路器记录
 */
export function resetBreaker(key: string) {
  // 从断路器映射中获取指定键的断路器记录
  const record = breakerMap.get(key);

  // 如果找到了对应的断路器记录，则进行重置操作
  if (record) {
    // 将失败计数重置为0
    record.failure = 0;
    // 将断路器关闭
    record.open = false;
    // 如果存在计时器，则清除之
    if (record.timer) clearTimeout(record.timer);
  }
}
